interface ObjOpt {
  id: string
  src: string
}
interface SourceLoaderOpt {
  list: Array<ObjOpt>
}
interface CallbackOpt {
  complate: Array<Function>
  progress: Array<Function>
}
export default class SourceLoader {
  private list: Array<ObjOpt>
  private limit: number = 0
  private success: Array<any> = []
  private error: Array<any> = []
  private callback: CallbackOpt = { complate: [], progress: [] }
  constructor(opt: SourceLoaderOpt) {
    this.list = opt.list || []
  }

  /**
   * 开始加载
   */
  start() {
    if (this.list.length) {
      this.list.forEach((e) => {
        if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/.test(e.src)) {
          const audio = this.loadAudio(e)
          audio.oncanplay = () => {
            const res = { source: audio, ...e }
            this.success.push(res)
            this.loadNum(res)
          }

          audio.onerror = () => {
            const res = { source: audio, ...e }
            this.error.push(res)
            this.loadNum(res)
          }
        }
        if (/\.(png|jpe?g|gif|svg)(\?.*)?$/.test(e.src)) {
          const img = this.loadImg(e)
          img.onload = () => {
            const res = { source: img, ...e }
            this.success.push(res)
            this.loadNum(res)
          }
          img.onerror = () => {
            const res = { source: img, ...e }
            this.error.push(res)
            this.loadNum(res)
          }
        }
      })
    }
    return this
  }

  /**
   * 加载img
   */
  loadImg(obj: ObjOpt) {
    const img: any = new Image()
    img.src = obj.src
    return img
  }

  /**
   * 加载audio
   */
  loadAudio(obj: ObjOpt) {
    const audio: any = new Audio()
    audio.volume = 0
    audio.src = obj.src
    audio.autoplay = true
    return audio
  }

  /**
   * 监听
   * @param name complate | progress
   * @param fn
   */
  on(name: 'complate' | 'progress', fn: Function) {
    this.callback[name].push(fn)
  }

  /**
   *
   * @param id
   * @returns
   */
  getSource(id: string): object | Array<object> | null {
    if (id) {
      const res = this.success.find((e: any) => e.id === id)
      return (res && res.source) || null
    }
    return this.success
  }

  /**
   * 加载计数器
   * @param res
   */
  loadNum(res: any) {
    this.limit++
    if (this.limit == this.list.length) {
      this.callback.complate.forEach((e: Function) => e && e(this.success))
    }
    this.callback.progress.forEach(
      (e: Function) => e && e({ ...res, val: this.limit / this.list.length })
    )
  }
}
